package com.example.demo.service.impl;

import com.example.demo.constant.Constant;
import com.example.demo.constant.ResponseCode;
import com.example.demo.entity.OperatorEntity;
import com.example.demo.exception.DemoServiceException;
import com.example.demo.param.LoginParam;
import com.example.demo.param.OperatorFindAllParam;
import com.example.demo.param.OperatorSaveParam;
import com.example.demo.param.OperatorUpdateParam;
import com.example.demo.repository.OperatorRepository;
import com.example.demo.service.OperatorService;
import com.example.demo.util.JWTUtil;
import com.example.demo.util.MapUtil;
import com.example.demo.util.ResultUtil;
import com.example.demo.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Service
@Transactional
public class OperatorServiceImpl implements OperatorService {

    @Autowired
    private OperatorRepository operatorRepository;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public ApiResult<Long> save(OperatorSaveParam operatorSaveParam) throws Exception {
        Integer count = operatorRepository.countByUsernameEqualsAndDelSignNot(operatorSaveParam.getUsername(), Constant.DEL_SIGN_IS);
        if(count > 0){
            throw new DemoServiceException(ResponseCode.OPERATOR_USERNAME_HAS_BEEN_EXIST);
        }
        OperatorEntity operatorEntity = new OperatorEntity();
        BeanUtils.copyProperties(operatorSaveParam, operatorEntity);
        operatorRepository.save(operatorEntity);
        return ResultUtil.success(operatorEntity.getId());
    }

    @Override
    public ApiResult<Long> update(OperatorUpdateParam operatorUpdateParam) throws Exception {
        Optional<OperatorEntity> operatorEntity = operatorRepository.findById(operatorUpdateParam.getId());
        if(!operatorEntity.isPresent()){
            throw new DemoServiceException(ResponseCode.OPERATOR_NOT_EXIST);
        }
        BeanUtils.copyProperties(operatorUpdateParam, operatorEntity.get());
        operatorRepository.save(operatorEntity.get());
        return ResultUtil.success(operatorEntity.get().getId());
    }

    @Override
    public ApiResult<OperatorVO> findById(Long id) throws Exception {
        Optional<OperatorEntity> operatorEntity = operatorRepository.findById(id);
        if(!operatorEntity.isPresent()){
            throw new DemoServiceException(ResponseCode.OPERATOR_NOT_EXIST);
        }
        OperatorVO operatorVO = new OperatorVO();
        BeanUtils.copyProperties(operatorEntity.get(), operatorVO);
        return ResultUtil.success(operatorVO);
    }

    @Override
    public ApiResult<Long> deleteById(Long id) throws Exception {
        Optional<OperatorEntity> operatorEntity = operatorRepository.findById(id);
        if(!operatorEntity.isPresent()){
            throw new DemoServiceException(ResponseCode.OPERATOR_NOT_EXIST);
        }
        if(operatorEntity.get().getDelSign() == Constant.DEL_SIGN_IS){
            throw new DemoServiceException(ResponseCode.OPERATOR_USERNAME_HAS_BEEN_DELETED);
        }
        operatorEntity.get().setDelSign(Constant.DEL_SIGN_IS);
        operatorRepository.save(operatorEntity.get());
        return ResultUtil.success(operatorEntity.get().getId());
    }

    @Override
    public ApiResult<PageVO<OperatorPageVO>> findAll(OperatorFindAllParam operatorFindAllParam) throws Exception {
        Pageable pageable = PageRequest.of((operatorFindAllParam.getPage() - 1), operatorFindAllParam.getSize(),
                Sort.Direction.fromString(operatorFindAllParam.getDirection()),
                operatorFindAllParam.getProperties());
        Page<Map<String, Object>> page = operatorRepository.findAll(operatorFindAllParam.getUsername(), Constant.DEL_SIGN_NOT, pageable);
        PageVO<OperatorPageVO> result = new PageVO<>();
        result.setTotalCount(page.getTotalElements());
        result.setList(MapUtil.mapsToObjects(page.getContent(), OperatorPageVO.class));
        return ResultUtil.success(result);
    }

    @Override
    public ApiResult<LoginVO> login(LoginParam loginParam, Long ip) throws Exception {
        List<OperatorEntity> list = operatorRepository.findAllByUsernameEqualsAndDelSignNot(loginParam.getUsername(), Constant.DEL_SIGN_IS);
        if (list == null || list.size() == 0){
            throw new DemoServiceException(ResponseCode.OPERATOR_USERNAME_NOT_EXIST);
        }else if(list.size() == 1){
            OperatorEntity operatorEntity = list.get(0);
            if(!operatorEntity.getPassword().equals(loginParam.getPassword())){
                throw new DemoServiceException(ResponseCode.OPERATOR_PASSWORD_IS_WRONG);
            }
            String token = JWTUtil.getToken(operatorEntity.getId(), operatorEntity.getUsername());
            redisTemplate.opsForValue().set("token"+operatorEntity.getId().toString(), token, 60, TimeUnit.MINUTES);
            operatorEntity.setLastLoginIP(ip);
            operatorEntity.setLoginTimes(operatorEntity.getLoginTimes()+1);
            operatorRepository.save(operatorEntity);
            LoginVO loginVO = new LoginVO();
            loginVO.setToken(token);
            return ResultUtil.success(loginVO);
        }else{
            throw new DemoServiceException(ResponseCode.OPERATOR_USERNAME_HAS_MORE);
        }
    }
}
